// ----------------------------------------------------------------------------//
// SQliteDataAccess.java
// Created by user On 2012-10-16
package com.demo.framework.db;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

/**
 * 封装 Android Sqlite 数据库操作，使用SqliteUtils中的方法实现。
 */

public class SqliteDatabaseAccess extends SQLiteOpenHelper implements DatabaseAccess {
    static private final Logger LOG = LoggerFactory.getLogger(SqliteDatabaseAccess.class);

    private List<DatabaseTrigger> dbtriggers = new ArrayList<DatabaseTrigger>();

    private boolean rethrowException = false;

    public SqliteDatabaseAccess(Context context, String name, int version) {
        super(context, name, null, version);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * android.database.sqlite.SQLiteOpenHelper#onCreate(android.database.sqlite
     * .SQLiteDatabase)
     */
    @Override
    public void onCreate(SQLiteDatabase db) {
        LOG.info("[onCreate] 创建数据库 PATH = {} VERSION = {} ...", db.getPath(), db.getVersion());
        try {
            createDatabase(db, db.getVersion());
        }
        catch(RuntimeException e) {
            LOG.error("[onCreate] 创建数据库失败", e);
            throw e; // 重新抛出异常，使得SqliteOpenHelper能够回滚事务
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * android.database.sqlite.SQLiteOpenHelper#onUpgrade(android.database.sqlite
     * .SQLiteDatabase, int, int)
     */
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        LOG.info("[onCreate] 数据库升级 PATH = {} VERSION = {} ...", db.getPath(), db.getVersion());
        try {
            cleanDatabase(db, oldVersion);
        }
        catch(RuntimeException e) {
            LOG.error("[onCreate] 创建数据库失败", e);
            throw e; // 重新抛出异常，使得SqliteOpenHelper能够回滚事务
        }
    }

    public void createDatabase(SQLiteDatabase db, int version) {
        // do nothing
    }

    public void cleanDatabase(SQLiteDatabase db, int version) {
        // do nothing
    }

    @Override
    public void addTrigger(DatabaseTrigger trigger) {
        assert trigger != null;
        dbtriggers.add(trigger);
    }

    protected void _onQueryError(RuntimeException e) {
        LOG.error("[DB ERROR]", e);
        if (rethrowException)
            throw e;
    }

    // ------------------------------------------------------------------------------
    // DatabaseAccess methods

    @Override
    public void setRethrowQueryException(boolean rethrowException) {
        this.rethrowException = rethrowException;
    }

    @Override
    public synchronized long insert(String tableName, ContentValues values) {
        for (DatabaseTrigger t : dbtriggers) {
            t.beforeInsert(this, tableName, values);
        }
        long rowid = insertWithoutTrigger(tableName, values);
        for (DatabaseTrigger t : dbtriggers) {
            t.afterInsert(this, tableName, values, rowid);
        }
        return rowid;
    }

    public synchronized long insertWithoutTrigger(String tableName, ContentValues values) {
        return SqliteUtils.insert(getWritableDatabase(), tableName, values);
    }

    public synchronized int updateWithoutTrigger(String tableName, ContentValues values, String whereClause,
            String... whereArgs) {
        return SqliteUtils.update(getWritableDatabase(), tableName, values, whereClause, whereArgs);
    }

    @Override
    public synchronized int update(String tableName, ContentValues values, String whereClause, String... whereArgs) {
        for (DatabaseTrigger t : dbtriggers) {
            t.beforeUpdate(this, tableName, values);
        }
        int n = SqliteUtils.update(getWritableDatabase(), tableName, values, whereClause, whereArgs);
        for (DatabaseTrigger t : dbtriggers) {
            t.afterUpdate(this, tableName, values, n);
        }
        return n;
    }

    public synchronized long insertQuitely(String tableName, ContentValues values) {
        try {
            return insert(tableName, values);
        }
        catch(Exception e) {
            LOG.error("[DB Error] Failed to do INSERT", e);
        }
        return -1;
    }

    public int updateQuitely(String tableName, ContentValues values, String whereClause, String... whereArgs) {
        try {
            return update(tableName, values, whereClause, whereArgs);
        }
        catch(Exception e) {
            LOG.error("[DB Error] Failed to do UPDATE", e);
        }
        return -1;
    }

    @Override
    public void execSQL(String sql) {
        SqliteUtils.execSQL(getReadableDatabase(), sql);
    }

    @Override
    public synchronized void createTableIfNoExists(String tableName, String[] columns) {
//        SqliteUtils.createTableIfNoExists(getWritableDatabase(), tableName, columns);
    }

    @Override
    public synchronized void dropTableIfExists(String tableName) {
        SqliteUtils.dropTableIfExists(getWritableDatabase(), tableName);
    }

    @Override
    public void queryWithHandler(String sql, QueryResultHandler<Void> rh, String... args) {
        SqliteUtils.queryWithHandler(getReadableDatabase(), sql, rh, args);
    }

    @Override
    public Cursor query(String sql, String... args) {
        try {
            return SqliteUtils.query(getReadableDatabase(), sql, args);
        }
        catch(RuntimeException e) {
            _onQueryError(e);
        }
        return null;
    }

    @Override
    public <T> T queryObject(String sql, QueryResultHandler<T> objq, String... args) {
        try {
            return SqliteUtils.queryObject(getReadableDatabase(), sql, objq, args);
        }
        catch(RuntimeException e) {
            _onQueryError(e);
        }
        return null;
    }

    @SuppressWarnings("unchecked")
    @Override
    public <T> List<T> queryList(String sql, QueryResultHandler<T> objq, String... args) {
        try {
            return SqliteUtils.queryList(getReadableDatabase(), sql, objq, args);
        }
        catch(RuntimeException e) {
            _onQueryError(e);
        }
        return (List<T>) Collections.EMPTY_LIST;
    }

    @Override
    public List<String[]> queryStringsList(String sql, String... args) {
        return queryList(sql, DB.QSTRINGS, args);
    }

    @Override
    public String[] queryStrings(String sql, String... args) {
        return queryObject(sql, DB.QSTRINGS, args);
    }

    @Override
    public int queryNumber(String sql, String... args) {
        return queryObject(sql, DB.QINT, args);
    }

    @Override
    public String newUniqueID() {
        return SqliteUtils.newID();
    }

    @Override
    public void beginTransaction() {
        getWritableDatabase().beginTransaction();
    }

    @Override
    public void setTransactionSuccessful() {
        getWritableDatabase().setTransactionSuccessful();
    }

    @Override
    public void endTransaction() {
        getWritableDatabase().endTransaction();
    }

    public void closeDB() {
        LOG.info("Closing Database");
        super.close();
    }
}

// ----------------------------------END---------------------------------------//